package demo.spring.core;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.dom4j.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.google.common.collect.HashBiMap;

import demo.spring.annotion.Resource;

/**
 * 解析配置文件类
 * @author songfeifei
 *
 */
public class ConfigResolver extends ApplicationEvent implements ApplicationEventMulticaster {

	private String configXml="spring.xml";
	static HashMap<String,Object> BeanFactory;//模仿BeanFactory 将所有的bean用beanid与对应实例用map保存起来
	static HashMap<String,ApplicationListener> RegistryListener;//这里保存那些是监听者的bean
	static {
		BeanFactory=new HashMap<>();
		RegistryListener=new HashMap<>();
	}
	
	public ConfigResolver(String config) {
		configXml=config==null ? configXml :config;//默认是spring.xml
		setConfigLocations(config);
		refresh();
	}
	
	public Object getBean(String beanid){
		return BeanFactory.get(beanid);
	}
	
	public void setConfigLocations(String configXml){
		//什么都不做 也可以做一些环境的检查 将配置的提取用一个类去处理
	}
	
	private void refresh(){
		invokeBeanFactoryPostProcessors(BeanFactory);
		registerListenters();//登记监听者
		finishRefresh();//
	}
	
	private void finishRefresh(){
		publishEvent(this);
	}
	
	/**
	 * 从beanfactory找到那些事监听者类型的bean
	 */
	private void registerListenters(){
		Iterator<String> it=BeanFactory.keySet().iterator();
		while(it.hasNext()){
			String key=it.next();
			if(BeanFactory.get(key) instanceof ApplicationListener){
				RegistryListener.put(key, (ApplicationListener)BeanFactory.get(key));
				it.remove();
			}
		}
		
	}
	
	/*
	 * 将配置文件中的bean全部实例化到map里面
	 */
	private void invokeBeanFactoryPostProcessors(HashMap beanFactory){
		InputStream in=null;
		try {
			in=ConfigResolver.class.getResourceAsStream(configXml)==null ? 
					new FileInputStream(configXml) : ConfigResolver.class.getResourceAsStream(configXml);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		
	
		try {
			DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
			org.w3c.dom.Document dc=db.parse(in);
			NodeList nl=dc.getElementsByTagName("bean");
			for(int i=0;i<nl.getLength();i++){
				NamedNodeMap attrs=nl.item(i).getAttributes();
				HashMap<String, String> beanMap=new HashMap<>();//对应一个bean标签
				for(int j=0;j<attrs.getLength();j++){
					String beanNodeName=attrs.item(j).getNodeName();
					String beanNodeValue=null;
					if(beanNodeName!=null){
						beanNodeValue=attrs.item(j).getNodeValue();
					}
					if(beanNodeValue!=null){
						beanMap.put(beanNodeName, beanNodeValue);
					}
				}
				String beanId=beanMap.get("id");
				String beanClass=beanMap.get("class");
				if(beanClass==null || beanId==null){
					continue;
				}
				
				Class cls;
				try {
					cls = Class.forName(beanClass);
					Object beanObject=cls.newInstance();
					Field[] fds=beanObject.getClass().getDeclaredFields();
					for(Field fd:fds){
						fd.setAccessible(true);//获取访问有变量权限
						Resource rs=fd.getAnnotation(Resource.class);
						if(rs!=null){
							fd.set(beanObject, fd.getType().newInstance());
						}
					}
					beanFactory.put(beanId, beanObject);
				} catch (ClassNotFoundException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	
	
	@Override
	public void publishEvent(ApplicationEvent event) {
		Iterator<String> it=RegistryListener.keySet().iterator();
		while(it.hasNext()){
			RegistryListener.get(it.next()).onApplicationEvent(event);
		}
	}

}
